﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LWH.ByteProtocol
{
    /// <summary>
    /// 各种类型与Byte转换的工具类
    /// </summary>
    public class ByteConverter
    {
        public enum ByteOrder
        {
            BIG_ENDIAN,
            LITTLE_ENDIAN
        }

        public enum StringEncoding
        {
            UTF8,
            ASCII,
            BigEndianUnicode,
            Unicode
        }

        #region Bytes To Value
        public static int getInt(byte[] src, int offset, ByteOrder order = ByteOrder.BIG_ENDIAN)
        {
            byte[] dataArray = src;
            

            if (!isCorrectOrder(order))
            {
                dataArray = (byte[])src.Clone();
                Array.Reverse(dataArray, offset, 4);
            }

            return BitConverter.ToInt32(dataArray, offset);

        }

        public static long getLong(byte[] src, int offset, ByteOrder order = ByteOrder.BIG_ENDIAN)
        {
            byte[] dataArray = src;


            if (!isCorrectOrder(order))
            {
                dataArray = (byte[])src.Clone();
                Array.Reverse(dataArray, offset, 8);
            }

            return BitConverter.ToInt64(dataArray, offset);
        }

        public static short getShort(byte[] src, int offset, ByteOrder order = ByteOrder.BIG_ENDIAN)
        {
            byte[] dataArray = src;


            if (!isCorrectOrder(order))
            {
                dataArray = (byte[])src.Clone();
                Array.Reverse(dataArray, offset, 2);
            }

            return BitConverter.ToInt16(dataArray, offset);
        }

        public static float getFloat(byte[] src, int offset, ByteOrder order = ByteOrder.BIG_ENDIAN)
        {

            byte[] dataArray = src;


            if (!isCorrectOrder(order))
            {
                dataArray = (byte[])src.Clone();
                Array.Reverse(dataArray,offset,4);
            }

            return BitConverter.ToSingle(dataArray, offset);
        }

        public static double getDouble(byte[] src, int offset, ByteOrder order = ByteOrder.BIG_ENDIAN)
        {

            byte[] dataArray = src;

            if (!isCorrectOrder(order))
            {
                dataArray = (byte[])src.Clone();
                Array.Reverse(dataArray, offset, 8);
            }

            return BitConverter.ToDouble(dataArray, offset);
        }

        public static string getString(byte[] src, int offset, int length, StringEncoding encoding = StringEncoding.UTF8)
        {
            
            switch (encoding)
            {
                case StringEncoding.UTF8:
                    return Encoding.UTF8.GetString(src, offset, length);
                case StringEncoding.BigEndianUnicode:
                    return Encoding.BigEndianUnicode.GetString(src, offset, length);
                case StringEncoding.ASCII:
                    return Encoding.ASCII.GetString(src, offset, length);
                case StringEncoding.Unicode:
                    return Encoding.Unicode.GetString(src, offset, length);
            }

            return null;   
        }

        #endregion

        #region Value To Bytes

        public static byte[] getBytes(int value, ByteOrder order = ByteOrder.BIG_ENDIAN)
        {
            byte[] convertByte = BitConverter.GetBytes(value);
            if (!isCorrectOrder(order))
            {
                Array.Reverse(convertByte);
            }
            return convertByte;
        }

        public static byte[] getBytes(long value, ByteOrder order = ByteOrder.BIG_ENDIAN)
        {
            byte[] convertByte = BitConverter.GetBytes(value);
            if (!isCorrectOrder(order))
            {
                Array.Reverse(convertByte);
            }
            return convertByte;
        }

        public static byte[] getBytes(short value, ByteOrder order = ByteOrder.BIG_ENDIAN)
        {
            byte[] convertByte = BitConverter.GetBytes(value);
            if (!isCorrectOrder(order))
            {
                Array.Reverse(convertByte);
            }
            return convertByte;
        }

        public static byte[] getBytes(float value, ByteOrder order = ByteOrder.BIG_ENDIAN)
        {
            byte[] convertByte = BitConverter.GetBytes(value);
            if (!isCorrectOrder(order))
            {
                Array.Reverse(convertByte);
            }
            return convertByte;
        }

        public static byte[] getBytes(double value, ByteOrder order = ByteOrder.BIG_ENDIAN)
        {
            byte[] convertByte = BitConverter.GetBytes(value);
            if (!isCorrectOrder(order))
            {
                Array.Reverse(convertByte);
            }
            return convertByte;
        }

        public static byte[] getBytes(string value,StringEncoding encoding = StringEncoding.UTF8)
        {
            switch(encoding)
            {
                case StringEncoding.UTF8:
                    return Encoding.UTF8.GetBytes(value);
                case StringEncoding.ASCII:
                    return Encoding.ASCII.GetBytes(value);
                case StringEncoding.Unicode:
                    return Encoding.Unicode.GetBytes(value);
                case StringEncoding.BigEndianUnicode:
                    return Encoding.BigEndianUnicode.GetBytes(value);
            }
            return null;
             
        }

        #endregion

        #region Value to dst Bytes

        public static void putValue(int value, byte[] dst, int offset, ByteOrder order = ByteOrder.BIG_ENDIAN)
        {
            byte[] src = getBytes(value,order);
            Buffer.BlockCopy(src, 0, dst, offset, src.Length);
        }

        public static void putValue(long value, byte[] dst, int offset, ByteOrder order = ByteOrder.BIG_ENDIAN)
        {
            byte[] src = getBytes(value, order);
            Buffer.BlockCopy(src,0, dst,offset, src.Length);
        }

        public static void putValue(short value, byte[] dst, int offset, ByteOrder order = ByteOrder.BIG_ENDIAN)
        {
            byte[] src = getBytes(value, order);
            Buffer.BlockCopy(src, 0, dst, offset, src.Length);
        }

        public static void putValue(float value, byte[] dst, int offset, ByteOrder order = ByteOrder.BIG_ENDIAN)
        {

            byte[] src = getBytes(value, order);
            Buffer.BlockCopy(src, 0, dst, offset, src.Length);
        }

        public static void putValue(double value, byte[] dst, int offset, ByteOrder order = ByteOrder.BIG_ENDIAN)
        {

            byte[] src = getBytes(value, order);
            Buffer.BlockCopy(src, 0, dst, offset, src.Length);
        }

        #endregion

        static bool isCorrectOrder(ByteOrder order)
        {
            return (order == ByteOrder.LITTLE_ENDIAN) == BitConverter.IsLittleEndian;
        }


        static void copyBytes(byte[] src,int srcOffset, byte[] dst, int dstOffset, int length)
        {
            Buffer.BlockCopy(src, srcOffset, dst, dstOffset, length);
        }

        public static T[] copyOfRange<T>(T[] src, int start, int end)
        {
            int len = end - start;
            T[] dest = new T[len];
            Buffer.BlockCopy(src, start, dest, 0, len);
            return dest;
        }
    }



}
